#include <cmath>
#include <OpenGL/gl.h>

#include "core.h"
#include "screen.h"
#include "keyboard.h"

ScreenManager::ScreenManager(Screen *start_screen) {
    ScreenState s1 = {
        start_screen,
        1.0,
        TRANSITION_NONE,
        true
    };
    ScreenState s0 = {
        0, 0.0, TRANSITION_NONE, false
    };
    current = s1;
    previous = s0;
}

void ScreenManager::TransitionToScreen(Screen *screen, TransitionType t) {
    ScreenState s0 = {
        current.screen,
        0.0,
        t,
        false        
    };
    ScreenState s1 = {
        screen,
        0.0,
        t,
        true
    };
    current = s1;
    previous = s0;
}

void popDrawState(ScreenState &s);
bool pushDrawState(ScreenState &s);

bool pushDrawState(ScreenState &s) {
    double x = 0.0, y = 0.0;
    double t = s.t * s.t;
    switch (s.tt) {
        case TRANSITION_LEFT:
            x = -SCREEN_WIDTH * t;
            if (s.current) x += SCREEN_WIDTH;
            glPushMatrix();
            glTranslatef(x, 0.0, 0.0);
            break;
        case TRANSITION_RIGHT:
            x = SCREEN_WIDTH * t;
            if (s.current) x -= SCREEN_WIDTH;
            glPushMatrix();
            glTranslatef(x, 0.0, 0.0);
            break;
        case TRANSITION_UP:
            y = SCREEN_HEIGHT * t;
            if (s.current) y -= SCREEN_HEIGHT;
            glPushMatrix();
            glTranslatef(0.0, y, 0.0);
            break;
        case TRANSITION_DOWN:
            y = -SCREEN_HEIGHT * t;
            if (s.current) y += SCREEN_HEIGHT;
            glPushMatrix();
            glTranslatef(0.0, y, 0.0);
            break;
        case TRANSITION_FADE_OUT:
            if (s.tt == TRANSITION_FADE_OUT && !s.current && s.t > 0.5) {
                return false;
            } else if (s.tt == TRANSITION_FADE_OUT && s.current && s.t <= 0.5) {
                return false;
            }
            glPushMatrix();
            break;
        default:
            glPushMatrix();
    }
    return true;
}
void popDrawState(ScreenState &s) {
    if (s.tt == TRANSITION_FADE_OUT) {
        double t = s.t;
        if (t > 0.5) t = 1 - t;
        t = 2 * t;
        SetColor(RGBA(0, 0, 0, 255 * t));
        glEnable(GL_BLEND);
        glBegin(GL_QUADS);
        glVertex2d(0, 0);
        glVertex2d(SCREEN_WIDTH, 0);
        glVertex2d(SCREEN_WIDTH, SCREEN_HEIGHT);
        glVertex2d(0, SCREEN_HEIGHT);
        glEnd();
        glDisable(GL_BLEND);
    }
    glPopMatrix();
    SetColor(RGBA(255, 255, 255, 255));
}

double transitionDuration(TransitionType tt);
double transitionDuration(TransitionType tt) {
    switch(tt) {
    case TRANSITION_FADE_OUT:
        return 1;
    default:
        return 0.25;
    }
}

void ScreenManager::Draw() {
    if (previous.screen) {
        if (pushDrawState(previous)) {
            previous.screen->Draw();
            popDrawState(previous);
        }
    }
    if (current.screen) {
        if(pushDrawState(current)) {
            current.screen->Draw();
            popDrawState(current);
        }
    }
}

void ScreenManager::Tick(double dt) {
    if (previous.screen) {
        previous.screen->Tick(dt, false);
        previous.t += dt / transitionDuration(previous.tt);
        if (previous.t >= 1) {
            previous.screen = 0;
        }
    }
    if (current.screen) {
        current.screen->Tick(dt, current.tt != TRANSITION_FADE_OUT);
        if (current.t < 1) {
            current.t += dt / transitionDuration(current.tt);
            if (current.t >= 1) {
                current.tt = TRANSITION_NONE;
                current.t = 1;
            }
        }
    }
}
